package com.haha.qqchannelbot.service;

import com.haha.qqchannelbot.core.entity.FileData;
import com.haha.qqchannelbot.core.entity.ReplyMessage;
import com.haha.qqchannelbot.core.utils.TextUtils;
import com.haha.qqchannelbot.entity.Bot;
import jakarta.annotation.Resource;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpHeaders;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedHashMap;
import java.util.Map;

@Service
public class BotHttpClient {

    @Resource
    private Bot bot;

    private HttpClient httpClient;

    private static final String BOUNDARY = "HahaBotBoundary";

    private static final String RN = "\r\n";

    public BotHttpClient() throws IOException, InterruptedException {
        HttpClient httpClient = HttpClient.newHttpClient();
        this.httpClient = httpClient;
    }

    public HttpResponse<String> sendPostJson(String url, String body) throws IOException, InterruptedException {
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(bot.getBaseUrl() + url))
                .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType()) // 设置请求头
                .header(HttpHeaders.AUTHORIZATION, bot.getToken())
                .POST(HttpRequest.BodyPublishers.ofString(body, Charset.forName("UTF-8")))
                .build();
        return httpClient.send(request, HttpResponse.BodyHandlers.ofString());
    }

    public HttpResponse<String> send(String url, String method, String body) throws IOException, InterruptedException {
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType()) // 设置请求头
                .header(HttpHeaders.AUTHORIZATION, bot.getToken())
                .method(method, HttpRequest.BodyPublishers.ofString(body))
                .build();
        return httpClient.send(request, HttpResponse.BodyHandlers.ofString());
    }


    public HttpResponse<String> sendPostFormData(String url, ReplyMessage replyMessage) throws Exception {

        HttpRequest.BodyPublisher bodyPublisher = HttpRequest.BodyPublishers.ofByteArray(createFormData(replyMessage));

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(bot.getBaseUrl() + url))
                .header(HttpHeaders.CONTENT_TYPE,
                        ContentType.MULTIPART_FORM_DATA.getMimeType() + "; boundary=" + BOUNDARY) // 设置请求头
                .header(HttpHeaders.AUTHORIZATION, bot.getToken())
                .POST(bodyPublisher)
                .build();
        return httpClient.send(request, HttpResponse.BodyHandlers.ofString());
    }

    public static void main(String[] args) throws Exception {

        FileData fileData = new FileData();
        fileData.setFileInputStream(new FileInputStream("1.jpeg"));
        fileData.setFileName("1.jpeg");

        Map<String, Object> map = new LinkedHashMap<>();
        map.put("msg_id", "08c5cacab4dcf0c3e92810f4c5fca20238b80248c4b2baac06");
        map.put("file_image", fileData);

        ReplyMessage replyMessage = new ReplyMessage();
        replyMessage.setMsgId("08c5cacab4dcf0c3e92810f4c5fca20238b80248c4b2baac06");
        replyMessage.setFileImage(fileData);
//        replyMessage.setContent("1111");
        HttpRequest.BodyPublisher bodyPublisher = HttpRequest.BodyPublishers.ofByteArray(createFormData(replyMessage));
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.sgroup.qq.com/channels/610214644/messages"))
                .header(HttpHeaders.CONTENT_TYPE,
                        ContentType.MULTIPART_FORM_DATA.getMimeType() + "; boundary=" + BOUNDARY) // 设置请求头
                .header(HttpHeaders.AUTHORIZATION, "Bot 102060483.hygG0AnAGlce52JvoUvh7x8bbYrYfKI9")
                .POST(bodyPublisher)
                .build();

        HttpClient httpClient = HttpClient.newHttpClient();
        HttpResponse<String> send = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(send.body());
    }

    /**
     * 拼接formdata
     * @param params
     * @return
     * @throws IOException
     */
    private static byte[] createFormData(Map<String, Object> params) throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        params.forEach((k, v) ->{
            try {
                outputStream.write(("--" + BOUNDARY + RN).getBytes(StandardCharsets.UTF_8));
                if (v instanceof String || v instanceof Integer) {
                    // Add the text parameter
                    outputStream.write(
                            ("Content-Disposition: form-data; name=\"" + k + "\"" + RN)
                                    .getBytes(StandardCharsets.UTF_8));
                    outputStream.write(RN.getBytes(StandardCharsets.UTF_8));
                    outputStream.write((v + RN).getBytes(StandardCharsets.UTF_8));
                }
                if (v instanceof FileData) {
                    // Add the file parameter
                    var fileF = (FileData) v;
                    outputStream.write(
                            ("Content-Disposition: form-data; name=\""+ k +"\"; filename=\""
                                    + fileF.getFileName() + "\"" + RN).getBytes(StandardCharsets.UTF_8));
                    outputStream.write(("Content-Type: " +
                            Files.probeContentType(Path.of(fileF.getFileName())) + RN)
                            .getBytes(StandardCharsets.UTF_8));
                    outputStream.write(RN.getBytes(StandardCharsets.UTF_8));
                    outputStream.write(fileF.getFileInputStream().readAllBytes());
                    outputStream.write(RN.getBytes(StandardCharsets.UTF_8));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        });

        // Add the final boundary
        outputStream.write(("--" + BOUNDARY + "--\r\n").getBytes(StandardCharsets.UTF_8));

        return outputStream.toByteArray();
    }

    /**
     * 拼接formdata
     * @param replyMessage
     * @return
     * @throws IOException
     */
    private static byte[] createFormData(ReplyMessage replyMessage) throws IOException, IllegalAccessException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        Field[] declaredFields = replyMessage.getClass().getDeclaredFields();

        for (Field declaredField : declaredFields) {

            declaredField.setAccessible(true);
            Object o = declaredField.get(replyMessage);
            if (o == null) {
                continue;
            }

            outputStream.write(("--" + BOUNDARY + RN).getBytes(StandardCharsets.UTF_8));

            if (o instanceof String || o instanceof Integer) {
                // Add the text parameter
                outputStream.write(
                        ("Content-Disposition: form-data; name=\"" +
                                TextUtils.camelToUnderline(declaredField.getName()) + "\"" + RN)
                                .getBytes(StandardCharsets.UTF_8));
                outputStream.write(RN.getBytes(StandardCharsets.UTF_8));
                outputStream.write((o + RN).getBytes(StandardCharsets.UTF_8));
            }
            if (o instanceof FileData) {
                // Add the file parameter
                var fileF = (FileData) o;
                outputStream.write(
                        ("Content-Disposition: form-data; name=\"" +
                                TextUtils.camelToUnderline(declaredField.getName()) + "\"; filename=\""
                                + fileF.getFileName() + "\"" + RN).getBytes(StandardCharsets.UTF_8));
                outputStream.write(("Content-Type: " +
                        Files.probeContentType(Path.of(fileF.getFileName())) + RN)
                        .getBytes(StandardCharsets.UTF_8));
                outputStream.write(RN.getBytes(StandardCharsets.UTF_8));
                outputStream.write(fileF.getFileInputStream().readAllBytes());
                outputStream.write(RN.getBytes(StandardCharsets.UTF_8));

            }
        }

        // Add the final boundary
        outputStream.write(("--" + BOUNDARY + "--\r\n").getBytes(StandardCharsets.UTF_8));

        return outputStream.toByteArray();
    }


}
